package com.lagou.edu;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

public class Bootstrap {

    /*
     * 完成Minicat 1.0版本
     * 需求：浏览器请求http://localhost:8080,返回⼀个固定的字符串到⻚
     * ⾯"Hello Minicat!"
     *
     * 完成Minicat 2.0版本
     * 需求：封装Request和Response对象，返回html静态资源⽂件
     *
     *
     * 完成Minicat 3.0版本
     * 需求：可以请求动态资源（Servlet）
     *
     * 完成Minicat 多线程改造
     *
     *
     *
     */
    private int port =8080;
    private Map<String,String> hostMap = new HashMap<>();

    private Map<String,Wrapper> contextMap = new HashMap<>();

    public Bootstrap() {
    }
    private void start(){
        try {
            ServerSocket serverSocket = new ServerSocket(port);
//            while(true){
//                Socket accept = serverSocket.accept();
//                String res = "Hello Minicat!";
//                OutputStream outputStream = accept.getOutputStream();
//                outputStream.write(HttpProtocolUtil.getSucceeText(res).getBytes(StandardCharsets.UTF_8));
//                outputStream.flush();
//                accept.close();
//            }
//            while(true){
//                Socket accept = serverSocket.accept();
//                InputStream inputStream = accept.getInputStream();
//                OutputStream outputStream = accept.getOutputStream();
//                Request request = new Request(inputStream);
//                Response response = new Response(outputStream);
//                response.outHtml(request.getUrl());
//                accept.close();
//            }


//            while(true){
//                Socket accept = serverSocket.accept();
//                InputStream inputStream = accept.getInputStream();
//                OutputStream outputStream = accept.getOutputStream();
//                Request request = new Request(inputStream);
//                Response response = new Response(outputStream);
//                if(servletMap.get(request.getUrl()) == null){
//                    response.outHtml(request.getUrl());
//                }else{
//                    HttpServlet httpServlet = servletMap.get(request.getUrl());
//                    httpServlet.service(request,response);
//                }
//                accept.close();
//            }

            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                    10,
                    10,
                    100L,
                    TimeUnit.SECONDS,
                    new ArrayBlockingQueue<Runnable>(50),
                    Executors.defaultThreadFactory(),
                    new RejectedExecutionHandler() {
                        @Override
                        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {

                        }
                    }
            );

            while(true){
                Socket accept = serverSocket.accept();
                RequestProcessor requestProcessor = new RequestProcessor(accept,contextMap);
//                threadPoolExecutor.execute(requestProcessor);
                requestProcessor.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

//    private void initServlet(){
//        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("web.xml");
//        SAXReader saxReader = new SAXReader();
//        try {
//            Document read = saxReader.read(resourceAsStream);
//            Element rootElement = read.getRootElement();
//            List<Element> servletElements = rootElement.selectNodes("//servlet");
//            Element element = servletElements.get(0);
//            Element servletName = (Element) element.selectSingleNode("servlet-name");
//            String servletNameValue = servletName.getStringValue();
//            Element servletClass = (Element) element.selectSingleNode("servlet-class");
//            String servletClassValue = servletClass.getStringValue();
//            Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name = '" + servletNameValue + "']");
//            String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
//            servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClassValue).newInstance());
//
//
//        } catch (DocumentException | ClassNotFoundException e) {
//            e.printStackTrace();
//        } catch (IllegalAccessException e) {
//            e.printStackTrace();
//        } catch (InstantiationException e) {
//            e.printStackTrace();
//        }
//
//    }
    private void initHost(){
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document read = saxReader.read(resourceAsStream);
            Element rootElement = read.getRootElement();
            List<Element> serviceList = rootElement.selectNodes("//service");
            Element connector = (Element) serviceList.get(0).selectSingleNode("Connector");
            String port = connector.attributeValue("port");
            //把初始化的端口放到这里
            this.port = Integer.valueOf(port);

            Element hostElement = (Element) rootElement.selectSingleNode("/Server/service/Engine/Host");
            String name = hostElement.attributeValue("name");
            String appBase = hostElement.attributeValue("appBase");
            //初始化获取到的localhost，和webapps路径
            hostMap.put(name,appBase);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    private void initContext(){
        String localhost = hostMap.get("localhost");

        //根据webapps的路径去初始化每个app的配置信息和httpServlet.class
        String path = "C:\\CodeTutorial" + localhost;
        File dir = new File(path);
        for(File file: dir.listFiles()){
            File webFile = new File(file.getAbsolutePath() + "/web.xml");
            if(webFile.exists()){
                try {
                    //这里是封装的wrapper，每个HttpServlet
                    Wrapper wrapper = parseWebXml(file.getAbsolutePath()+"\\server\\", new FileInputStream(webFile));
                    // 然后存储起来
                    //http://localhost:8080/   Demo2/    lagou
                    contextMap.put(file.getName(),wrapper);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    private Wrapper parseWebXml(String path,InputStream inputStream){
        SAXReader saxReader = new SAXReader();
        try {
            Document read = saxReader.read(inputStream);
            Element rootElement = read.getRootElement();
            List<Element> servletElements = rootElement.selectNodes("//servlet");
            Element element = servletElements.get(0);
            Element servletName = (Element) element.selectSingleNode("servlet-name");
            String servletNameValue = servletName.getStringValue();
            Element servletClass = (Element) element.selectSingleNode("servlet-class");
            String servletClassValue = servletClass.getStringValue();
            Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name = '" + servletNameValue + "']");
            String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
            //自定义classLoader读取webapp下的class文件
            MyClassLoader myClassLoader = new MyClassLoader(path);
            Class<?> aClass = myClassLoader.findClass(servletClassValue);
            //根据class文件和路径去封装到wrapper里面
            //http://localhost:8080/Demo2/     lagou
            return new Wrapper(urlPattern, (HttpServlet) aClass.newInstance());


        } catch (DocumentException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        //初始化server.xml
        bootstrap.initHost();
        bootstrap.initContext();
        bootstrap.start();
    }

}
